home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cpp.arc / CPP6.C < prev    next >
C/C++ Source or Header  |  1985-11-27  |  43KB  |  1,274 lines

  1.  
  2. /*
  3.  *                          C P P 6 . C
  4.  *              S u p p o r t   R o u t i n e s
  5.  *
  6.  * Edit History
  7.  * 25-May-84 MM         Added 8-bit support to type table.
  8.  * 30-May-84 ARF        sharp() should output filename in quotes
  9.  * 02-Aug-84 MM         Newline and #line hacking.  sharp() now in cpp1.c
  10.  * 31-Aug-84 MM         USENET net.sources release
  11.  * 11-Sep-84 ado/MM     Keepcomments, also line number pathological
  12.  * 12-Sep-84 ado/MM     bug if comment changes to space and we unget later.
  13.  * 03-Oct-84 gkr/MM     Fixed scannumber bug for '.e' (as in struct.element).
  14.  * 04-Oct-84 MM         Added ungetstring() for token concatenation
  15.  * 08-Oct-84 MM         Yet another attack on number scanning
  16.  * 31-Oct-84 ado        Parameterized $ in identifiers
  17.  *  2-Nov-84 MM         Token concatenation is messier than I thought
  18.  *  6-Dec-84 MM         \<nl> is everywhere invisible.
  19.  * 28-Mar-85 MM         Token concatenation redone again.
  20.  * 29-Mar-85 ado/MM     Trigraphs, Fixed bug with macros with / at
  21.  *                      the end: #define foo /$ ... $/
  22.  *  2-Apr-85 MM         Hacked trigraph code.
  23.  * 30-May-85 ado        Fixed bug in scannumber sign processing
  24.  */
  25.  
  26. #include        <stdio.h>
  27. #include        <ctype.h>
  28. #include        "cppdef.h"
  29. #include        "cpp.h"
  30.  
  31. /*
  32.  * skipnl()     skips over input text to the end of the line.
  33.  * skipws()     skips over "whitespace" (spaces or tabs), but
  34.  *              not skip over the end of the line.  It skips over
  35.  *              TOK_SEP, however (though that shouldn't happen).
  36.  * scanid()     reads the next token (C identifier) into token[].
  37.  *              The caller has already read the first character of
  38.  *              the identifier.  Unlike macroid(), the token is
  39.  *              never expanded.
  40.  * macroid()    reads the next token (C identifier) into token[].
  41.  *              If it is a #defined macro, it is expanded, and
  42.  *              macroid() returns TRUE, otherwise, FALSE.
  43.  * catenate()   Does the dirty work of token concatenation, TRUE if it did.
  44.  * scanstring() Reads a string from the input stream, calling
  45.  *              a user-supplied function for each character.
  46.  *              This function may be output() to write the
  47.  *              string to the output file, or save() to save
  48.  *              the string in the work buffer.
  49.  * scannumber() Reads a C numeric constant from the input stream,
  50.  *              calling the user-supplied function for each
  51.  *              character.  (output() or save() as noted above.)
  52.  * save()       Save one character in the work[] buffer.
  53.  * savestring() Saves a string in malloc() memory.
  54.  * getfile()    Initialize a new FILEINFO structure, called when
  55.  *              #include opens a new file, or a macro is to be
  56.  *              expanded.
  57.  * getmem()     Get a specified number of bytes from malloc memory.
  58.  * output()     Write one character to stdout (calling putchar) --
  59.  *              implemented as a function so its address may be
  60.  *              passed to scanstring() and scannumber().
  61.  * lookid()     Scans the next token (identifier) from the input
  62.  *              stream.  Looks for it in the #defined symbol table.
  63.  *              Returns a pointer to the definition, if found, or NULL
  64.  *              if not present.  The identifier is stored in token[].
  65.  * defnedel()   Define enter/delete subroutine.  Updates the
  66.  *              symbol table.
  67.  * get()        Read the next byte from the current input stream,
  68.  *              handling end of (macro/file) input and embedded
  69.  *              comments appropriately.  Note that the global
  70.  *              instring is -- essentially -- a parameter to get().
  71.  * cget()       Like get(), but skip over TOK_SEP.
  72.  * unget()      Push last gotten character back on the input stream.
  73.  * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
  74.  *              These routines format an print messages to the user.
  75.  *              cerror & cwarn take a format and a single string argument.
  76.  *              cierror & ciwarn take a format and a single int (char) argument. *              cfatal takes a format and a single string argument.
  77.  */
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99. /*
  100.  * This table must be rewritten for a non-Ascii machine.
  101.  *
  102.  * Note that several "non-visible" characters have special meaning:
  103.  * Hex 1C ST_QUOTE  -- magic " after # stringizing.
  104.  * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
  105.  * Hex 1E TOK_SEP   -- a delimiter for token concatenation
  106.  * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
  107.  */
  108. #if ST_QUOTE != 0x1C || DEF_MAGIC != 0x1D || TOK_SEP != 0x1E || COM_SEP != 0x1F
  109.         << error type table isn't correct >>
  110. #endif
  111.  
  112. #if OK_DOLLAR
  113. #define DOL     LET
  114. #else
  115. #define DOL     000
  116. #endif
  117.  
  118. char type[256] = {              /* Character type codes    Hex          */
  119.    END,   000,   000,   000,   000,   000,   000,   000, /* 00          */
  120.    000,   SPA,   000,   000,   000,   000,   000,   000, /* 08          */
  121.    000,   000,   000,   000,   000,   000,   000,   000, /* 10          */
  122.    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18          */
  123.    SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&' */
  124. OP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./ */
  125.    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567 */
  126.    DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */
  127.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG */
  128.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO */
  129.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW */
  130.    LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_ */
  131.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg */
  132.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno */
  133.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw */
  134.    LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~  */
  135.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  136.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  137.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  138.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  139.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  140.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  141.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  142.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
  143. };
  144.  
  145.  
  146.  
  147. skipnl()
  148. /*
  149.  * Skip to the end of the current input line.
  150.  */
  151. {
  152.         register int            c;
  153.  
  154.         do {                            /* Skip to newline      */
  155.             c = get();
  156.         } while (c != '\n' && c != EOF_CHAR);
  157. }
  158.  
  159. int
  160. skipws()
  161. /*
  162.  * Skip over whitespace
  163.  */
  164. {
  165.         register int            c;
  166.  
  167.         do {                            /* Skip whitespace      */
  168.             c = get();
  169. #if COMMENT_INVISIBLE
  170.         } while (type[c] == SPA || c == COM_SEP);
  171. #else
  172.         } while (type[c] == SPA);
  173. #endif
  174.         return (c);
  175. }
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195. scanid(c)
  196. register int    c;                              /* First char of id     */
  197. /*
  198.  * Get the next token (an id) into the token buffer.
  199.  * Note: this code is duplicated in lookid().
  200.  * Change one, change both.
  201.  */
  202. {
  203.         register char   *bp;
  204.  
  205.         if (c == DEF_MAGIC)                     /* Eat the magic token  */
  206.             c = get();                          /* undefiner.           */
  207.         bp = token;
  208.         do {
  209.             if (bp < &token[IDMAX])             /* token dim is IDMAX+1 */
  210.                 *bp++ = c;
  211.             c = get();
  212.         } while (type[c] == LET || type[c] == DIG);
  213.         unget();
  214.         *bp = EOS;
  215. }
  216.  
  217. int
  218. macroid(c)
  219. register int            c;
  220. /*
  221.  * If c is a letter, scan the id.  if it's #defined, expand it and scan
  222.  * the next character and try again.
  223.  *
  224.  * Else, return the character.  If type[c] is a LET, the token is in token.
  225.  */
  226. {
  227.         register DEFBUF *dp;
  228.  
  229.         if (infile != NULL && infile->fp != NULL)
  230.             recursion = 0;
  231.         while (type[c] == LET && (dp = lookid(c)) != NULL) {
  232.             expand(dp);
  233.             c = get();
  234.         }
  235.         return (c);
  236. }
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243. int
  244. catenate()
  245. /*
  246.  * A token was just read (via macroid).
  247.  * If cpp was compiled for no token concatenation or concatenation
  248.  * without reexpansion of the new token, return FALSE.
  249.  * Else, we plan to macro-expand the new token.  If the next
  250.  * character is TOK_SEP, concatenate the next token and return TRUE
  251.  * -- which should recall macroid after refreshing macroid's argument.
  252.  * If it is not TOK_SEP, unget() the character and return FALSE.
  253.  */
  254. {
  255. #if OK_CONCAT == CON_EXPAND
  256.         register int            c;
  257.         register char           *token1;
  258.         extern int              save();
  259.         extern char             *appendstring();
  260.  
  261.         if (get() != TOK_SEP) {                 /* Token concatenation  */
  262.             unget();
  263.             return (FALSE);
  264.         }
  265.         else {
  266.             /*
  267.              * The input stream is (had better be)
  268.              * # stuff #, where stuff is initially something
  269.              * to be concatenated.
  270.              */
  271.             token1 = savestring(token);         /* Save first token     */
  272.             while ((c = get()) != TOK_SEP) {    /* Off we go.           */
  273.                 if (c == EOF_CHAR)
  274.                     cfatal("EOF in token concatenation to \"%s\"", token1);
  275.                 c = macroid(c);                 /* Scan next token      */
  276.                 switch(type[c]) {               /* What was it?         */
  277.                 case LET:                       /* An identifier, ...   */
  278.                     token1 = appendstring(token1, token);
  279.                     break;
  280.  
  281.                 case DIG:                       /* A digit string       */
  282.                 case DOT:                       /* Other flavor digit   */
  283.                     workp = work;
  284.                     scannumber(c, save);
  285.                     *workp = EOS;
  286.                     token1 = appendstring(token1, work);
  287.                     break;
  288.  
  289.                 default:                        /* Who knows            */
  290.                     work[0] = c;
  291.                     work[1] = EOS;
  292.                     token1 = appendstring(token1, work);
  293.                     break;
  294.                 }
  295.             }
  296.             ungetstring(token1);                /* New thing to do      */
  297.             free(token1);                       /* Release scratch      */
  298.             return (TRUE);
  299.         }
  300. #else
  301.         return (FALSE);                         /* Not supported        */
  302. #endif
  303. }
  304.  
  305. #if OK_CONCAT == CON_EXPAND
  306. FILE_LOCAL char *
  307. appendstring(token1, text)
  308. char            *token1;                /* In malloc storage            */
  309. char            *text;                  /* Append it to token1          */
  310. {
  311.         extern char     *realloc();
  312.  
  313.         if ((token1 = realloc(token1,
  314.                 (unsigned) (strlen(token1) + strlen(text) + 1))) == NULL)
  315.             cfatal("Out of memory concatenating tokens", NULLST);
  316.         strcat(token1, text);
  317.         return (token1);
  318. }
  319. #endif
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339. int
  340. scanstring(delim, outfun)
  341. register int    delim;                  /* ' or "                       */
  342. int             (*outfun)();            /* Output function              */
  343. /*
  344.  * Scan off a string.  Warning if terminated by newline or EOF.
  345.  * outfun() outputs the character -- to a buffer if in a macro.
  346.  * TRUE if ok, FALSE if error.
  347.  */
  348. {
  349.         register int            c;
  350.  
  351.         instring = TRUE;                /* Don't strip comments         */
  352.         (*outfun)(delim);
  353.         while ((c = get()) != delim
  354.              && c != '\n'
  355.              && c != EOF_CHAR) {
  356.             (*outfun)(c);
  357.             if (c == '\\')
  358.                 (*outfun)(get());
  359.         }
  360.         instring = FALSE;
  361.         if (c == delim) {
  362.             (*outfun)(c);
  363.             return (TRUE);
  364.         }
  365.         else {
  366.             cerror("Unterminated string", NULLST);
  367.             unget();
  368.             return (FALSE);
  369.         }
  370. }
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387. scannumber(c, outfun)
  388. register int    c;                              /* First char of number */
  389. register int    (*outfun)();                    /* Output/store func    */
  390. /*
  391.  * Process a number.  We know that c is from 0 to 9 or dot.
  392.  * Algorithm from Dave Conroy's Decus C.
  393.  */
  394. {
  395.         register int    radix;                  /* 8, 10, or 16         */
  396.         int             expseen;                /* 'e' seen in floater  */
  397.         int             octal89;                /* For bad octal test   */
  398.         int             dotflag;                /* TRUE if '.' was seen */
  399.  
  400.         expseen = FALSE;                        /* No exponent seen yet */
  401.         octal89 = FALSE;                        /* No bad octal yet     */
  402.         radix = 10;                             /* Assume decimal       */
  403.         if ((dotflag = (c == '.')) != FALSE) {  /* . something?         */
  404.             (*outfun)('.');                     /* Always out the dot   */
  405.             if (type[(c = get())] != DIG) {     /* If not a float numb, */
  406.                 unget();                        /* Rescan strange char  */
  407.                 return;                         /* All done for now     */
  408.             }
  409.         }                                       /* End of float test    */
  410.         else if (c == '0') {                    /* Octal or hex?        */
  411.             (*outfun)(c);                       /* Stuff initial zero   */
  412.             radix = 8;                          /* Assume it's octal    */
  413.             c = get();                          /* Look for an 'x'      */
  414.             if (c == 'x' || c == 'X') {         /* Did we get one?      */
  415.                 radix = 16;                     /* Remember new radix   */
  416.                 (*outfun)(c);                   /* Stuff the 'x'        */
  417.                 c = get();                      /* Get next character   */
  418.             }
  419.         }
  420.         for (;;) {                              /* Process curr. char.  */
  421.             /*
  422.              * Note that this algorithm accepts "012e4" and "03.4"
  423.              * as legitimate floating-point numbers.
  424.              */
  425.             if (radix != 16 && (c == 'e' || c == 'E')) {
  426.                 if (expseen)                    /* Already saw 'E'?     */
  427.                     break;                      /* Exit loop, bad nbr.  */
  428.                 expseen = TRUE;                 /* Set exponent seen    */
  429.                 radix = 10;                     /* Decimal exponent     */
  430.                 (*outfun)(c);                   /* Output the 'e'       */
  431.                 if ((c = get()) != '+' && c != '-')
  432.                     continue;
  433.             }
  434.             else if (radix != 16 && c == '.') {
  435.                 if (dotflag)                    /* Saw dot already?     */
  436.                     break;                      /* Exit loop, two dots  */
  437.                 dotflag = TRUE;                 /* Remember the dot     */
  438.                 radix = 10;                     /* Decimal fraction     */
  439.             }
  440.             else {                              /* Check the digit      */
  441.                 switch (c) {
  442.                 case '8': case '9':             /* Sometimes wrong      */
  443.                     octal89 = TRUE;             /* Do check later       */
  444.                 case '0': case '1': case '2': case '3':
  445.                 case '4': case '5': case '6': case '7':
  446.                     break;                      /* Always ok            */
  447.  
  448.                 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  449.                 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  450.                     if (radix == 16)            /* Alpha's are ok only  */
  451.                         break;                  /* if reading hex.      */
  452.                 default:                        /* At number end        */
  453.                     goto done;                  /* Break from for loop  */
  454.                 }                               /* End of switch        */
  455.             }                                   /* End general case     */
  456.             (*outfun)(c);                       /* Accept the character */
  457.             c = get();                          /* Read another char    */
  458.         }                                       /* End of scan loop     */
  459.         /*
  460.          * When we break out of the scan loop, c contains the first
  461.          * character (maybe) not in the number.  If the number is an
  462.          * integer, allow a trailing 'L' for long and/or a trailing 'U'
  463.          * for unsigned.  If not those, push the trailing character back
  464.          * on the input stream.  Floating point numbers accept a trailing
  465.          * 'L' for "long double" or a trailing 'F' for explicit float.
  466.          */
  467. done:   if (dotflag || expseen) {               /* Floating point?      */
  468.             switch (c) {
  469.             case 'l':
  470.             case 'L':
  471.             case 'f':
  472.             case 'F':
  473.                 (*outfun)(c);                   /* Output the trailer   */
  474.                 c = get();                      /* Ungotten later       */
  475.                 break;
  476.  
  477.             default:                            /* Others are ignored   */
  478.                 break;
  479.             }
  480.         }
  481.         else {                                  /* Else it's an integer */
  482.             /*
  483.              * We know that dotflag and expseen are both zero, now:
  484.              *   dotflag signals "saw 'L'", and
  485.              *   expseen signals "saw 'U'".
  486.              * We assume that 12F is not a floating constant.
  487.              */
  488.             for (;;) {
  489.                 switch (c) {
  490.                 case 'l':
  491.                 case 'L':
  492.                     if (dotflag)
  493.                         goto nomore;
  494.                     dotflag = TRUE;
  495.                     break;
  496.  
  497.                 case 'u':
  498.                 case 'U':
  499.                     if (expseen)
  500.                         goto nomore;
  501.                     expseen = TRUE;
  502.                     break;
  503.  
  504.                 default:
  505.                     goto nomore;
  506.                 }
  507.                 (*outfun)(c);                   /* Got 'L' or 'U'.      */
  508.                 c = get();                      /* Look at next, too.   */
  509.             }
  510.         }
  511. nomore: unget();                                /* Not part of a number */
  512.         if (octal89 && radix == 8)
  513.             cwarn("Illegal digit in octal number", NULLST);
  514. }
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531. save(c)
  532. register int    c;
  533. {
  534.         if (workp >= &work[NWORK])
  535.             cfatal("Work buffer overflow", NULLST);
  536.         else *workp++ = c;
  537. }
  538.  
  539. char *
  540. savestring(text)
  541. char            *text;
  542. /*
  543.  * Store a string into free memory.
  544.  */
  545. {
  546.         register char   *result;
  547.  
  548.         result = getmem(strlen(text) + 1);
  549.         strcpy(result, text);
  550.         return (result);
  551. }
  552.  
  553. FILEINFO        *
  554. getfile(bufsize, name)
  555. int             bufsize;                /* Line or define buffer size   */
  556. char            *name;                  /* File or macro name string    */
  557. /*
  558.  * Common FILEINFO buffer initialization for a new file or macro.
  559.  */
  560. {
  561.         register FILEINFO       *file;
  562.  
  563.         file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize);
  564.         file->parent = infile;                  /* Chain files together */
  565.         file->fp = NULL;                        /* No file yet          */
  566.         file->filename = savestring(name);      /* Save file/macro name */
  567.         file->progname = NULL;                  /* No #line seen yet    */
  568.         file->unrecur = 0;                      /* No macro fixup       */
  569.         file->bptr = file->buffer;              /* Initialize line ptr  */
  570.         file->buffer[0] = EOS;                  /* Force first read     */
  571.         file->line = 0;                         /* (Not used just yet)  */
  572.         if (infile != NULL)                     /* If #include file     */
  573.             infile->line = line;                /* Save current line    */
  574.         infile = file;                          /* New current file     */
  575.         return (file);                          /* All done.            */
  576. }
  577.  
  578. char *
  579. getmem(size)
  580. int             size;
  581. /*
  582.  * Get a block of free memory.
  583.  */
  584. {
  585.         register char   *result;
  586.         extern char     *malloc();
  587.  
  588.         if ((result = malloc((unsigned) size)) == NULL)
  589.             cfatal("Out of memory", NULLST);
  590.         return (result);
  591. }
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603. /*
  604.  *                      C P P   S y m b o l   T a b l e s
  605.  */
  606.  
  607. /*
  608.  * SBSIZE defines the number of hash-table slots for the symbol table.
  609.  * It must be a power of 2.
  610.  */
  611. #ifndef SBSIZE
  612. #define SBSIZE  64
  613. #endif
  614. #define SBMASK  (SBSIZE - 1)
  615. #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
  616.         << error, SBSIZE must be a power of 2 >>
  617. #endif
  618.  
  619. static DEFBUF   *symtab[SBSIZE];        /* Symbol table queue headers   */
  620.  
  621. DEFBUF *
  622. lookid(c)
  623. int     c;                              /* First character of token     */
  624. /*
  625.  * Look for the next token in the symbol table.  Returns token in "token".
  626.  * If found, returns the table pointer;  Else returns NULL.
  627.  */
  628. {
  629.         register int            nhash;
  630.         register DEFBUF         *dp;
  631.         register char           *np;
  632.         int                     temp;
  633.         int                     isrecurse;      /* For #define foo foo  */
  634.  
  635.         np = token;
  636.         nhash = 0;
  637.         if ((isrecurse = (c == DEF_MAGIC)))     /* If recursive macro   */
  638.             c = get();                          /* hack, skip DEF_MAGIC */
  639.         do {
  640.             if (np < &token[IDMAX]) {           /* token dim is IDMAX+1 */
  641.                 *np++ = c;                      /* Store token byte     */
  642.                 nhash += c;                     /* Update hash value    */
  643.             }
  644.             c = get();                          /* And get another byte */
  645.         } while (type[c] == LET || type[c] == DIG);
  646.         unget();                                /* Rescan terminator    */
  647.         *np = EOS;                              /* Terminate token      */
  648.         if (isrecurse)                          /* Recursive definition */
  649.             return (NULL);                      /* undefined just now   */
  650.         nhash += (np - token);                  /* Fix hash value       */
  651.         dp = symtab[nhash & SBMASK];            /* Starting bucket      */
  652.         while (dp != (DEFBUF *) NULL) {         /* Search symbol table  */
  653.             if (dp->hash == nhash               /* Fast precheck        */
  654.              && (temp = strcmp(dp->name, token)) >= 0)
  655.                 break;
  656.             dp = dp->link;                      /* Nope, try next one   */
  657.         }
  658.         return ((temp == 0) ? dp : NULL);
  659. }
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675. DEFBUF *
  676. defendel(name, delete)
  677. char            *name;
  678. int             delete;                 /* TRUE to delete a symbol      */
  679. /*
  680.  * Enter this name in the lookup table (delete = FALSE)
  681.  * or delete this name (delete = TRUE).
  682.  * Returns a pointer to the define block (delete = FALSE)
  683.  * Returns NULL if the symbol wasn't defined (delete = TRUE).
  684.  */
  685. {
  686.         register DEFBUF         *dp;
  687.         register DEFBUF         **prevp;
  688.         register char           *np;
  689.         int                     nhash;
  690.         int                     temp;
  691.         int                     size;
  692.  
  693.         for (nhash = 0, np = name; *np != EOS;)
  694.             nhash += *np++;
  695.         size = (np - name);
  696.         nhash += size;
  697.         prevp = &symtab[nhash & SBMASK];
  698.         while ((dp = *prevp) != (DEFBUF *) NULL) {
  699.             if (dp->hash == nhash
  700.              && (temp = strcmp(dp->name, name)) >= 0) {
  701.                 if (temp > 0)
  702.                     dp = NULL;                  /* Not found            */
  703.                 else {
  704.                     *prevp = dp->link;          /* Found, unlink and    */
  705.                     if (dp->repl != NULL)       /* Free the replacement */
  706.                         free(dp->repl);         /* if any, and then     */
  707.                     free((char *) dp);          /* Free the symbol      */
  708.                 }
  709.                 break;
  710.             }
  711.             prevp = &dp->link;
  712.         }
  713.         if (!delete) {
  714.             dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
  715.             dp->link = *prevp;
  716.             *prevp = dp;
  717.             dp->hash = nhash;
  718.             dp->repl = NULL;
  719.             dp->nargs = 0;
  720.             strcpy(dp->name, name);
  721.         }
  722.         return (dp);
  723. }
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747. /*
  748.  *                      G E T
  749.  */
  750.  
  751. int
  752. get()
  753. /*
  754.  * Return the next character from a macro or the current file.
  755.  * Handle end of file from #include files.
  756.  */
  757. {
  758.         register int            c;
  759.         register FILEINFO       *file;
  760.         register int            popped;         /* Recursion fixup      */
  761.  
  762.         popped = 0;
  763. get_from_file:
  764.         if ((file = infile) == NULL)
  765.             return (EOF_CHAR);
  766. newline:
  767. #if DEBUG
  768.         if (debug > 2) {
  769.             printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",                file->filename, recursion, line,
  770.                 file->bptr - file->buffer, file->buffer);
  771.             dumpunget("get entrance");
  772.         }
  773. #endif
  774.         /*
  775.          * Read a character from the current input line or macro.
  776.          * At EOS, either finish the current macro (freeing temp.
  777.          * storage) or read another line from the current input file.
  778.          * At EOF, exit the current file (#include) or, at EOF from
  779.          * the cpp input file, return EOF_CHAR to finish processing.
  780.          */
  781.         if ((c = *file->bptr++ & 0xFF) == EOS) {
  782.             /*
  783.              * Nothing in current line or macro.  Get next line (if
  784.              * input from a file), or do end of file/macro processing.
  785.              * In the latter case, jump back to restart from the top.
  786.              */
  787.             if (file->fp == NULL) {             /* NULL if macro        */
  788.                 popped++;
  789.                 recursion -= file->unrecur;
  790.                 if (recursion < 0)
  791.                     recursion = 0;
  792.                 infile = file->parent;          /* Unwind file chain    */
  793.             }
  794.             else {                              /* Else get from a file */
  795.                 if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
  796.                         != NULL) {
  797. #if DEBUG
  798.                     if (debug > 1) {            /* Dump it to stdout    */
  799.                         printf("\n#line %d (%s), %s",
  800.                             line, file->filename, file->buffer);
  801.                     }
  802. #endif
  803. #if OK_TRIGRAPH
  804.                     if (tflag)
  805.                         trigraph(file->buffer);
  806. #endif
  807.                     goto newline;               /* process the line     */
  808.                 }
  809.                 else {
  810.                     fclose(file->fp);           /* Close finished file  */
  811.                     if ((infile = file->parent) != NULL) {
  812.                         /*
  813.                          * There is an "ungotten" newline in the current
  814.                          * infile buffer (set there by doinclude() in
  815.                          * cpp1.c).  Thus, we know that the mainline code
  816.                          * is skipping over blank lines and will do a
  817.                          * #line at its convenience.
  818.                          */
  819.                         wrongline = TRUE;       /* Need a #line now     */
  820.                     }
  821.                 }
  822.             }
  823.             /*
  824.              * Free up space used by the (finished) file or macro and
  825.              * restart input from the parent file/macro, if any.
  826.              */
  827.             free(file->filename);               /* Free name and        */
  828.             if (file->progname != NULL)         /* if a #line was seen, */
  829.                 free(file->progname);           /* free it, too.        */
  830.             free((char *) file);                /* Free file space      */
  831.             if (infile == NULL)                 /* If at end of file    */
  832.                 return (EOF_CHAR);              /* Return end of file   */
  833.             line = infile->line;                /* Reset line number    */
  834.             goto get_from_file;                 /* Get from the top.    */
  835.         }
  836.         /*
  837.          * Common processing for the new character.
  838.          */
  839.         if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */
  840.             goto newline;                       /* from a file          */
  841.         if (file->parent != NULL) {             /* Macro or #include    */
  842.             if (popped != 0)
  843.                 file->parent->unrecur += popped;
  844.             else {
  845.                 recursion -= file->parent->unrecur;
  846.                 if (recursion < 0)
  847.                     recursion = 0;
  848.                 file->parent->unrecur = 0;
  849.             }
  850.         }
  851.         if (c == '\n')                          /* Maintain current     */
  852.             ++line;                             /* line counter         */
  853.         if (instring)                           /* Strings just return  */
  854.             return (c);                         /* the character.       */
  855.         else if (c == '/' && *file->bptr != EOS) { /* Comment?          */
  856.             instring = TRUE;                    /* So get() won't loop  */
  857.             if ((c = get()) != '*') {           /* Next byte '*'?       */
  858.                 instring = FALSE;               /* Nope, no comment     */
  859.                 unget();                        /* Push the char. back  */
  860.                 return ('/');                   /* Return the slash     */
  861.             }
  862.             if (keepcomments) {                 /* If writing comments  */
  863.                 putchar('/');                   /* Write out the        */
  864.                 putchar('*');                   /*   initializer        */
  865.             }
  866.             for (;;) {                          /* Eat a comment        */
  867.                 c = get();
  868. test:           if (keepcomments && c != EOF_CHAR)
  869.                     cput(c);
  870.                 switch (c) {
  871.                 case EOF_CHAR:
  872.                     cerror("EOF in comment", NULLST);
  873.                     return (EOF_CHAR);
  874.  
  875.                 case '/':
  876.                     if ((c = get()) != '*')     /* Don't let comments   */
  877.                         goto test;              /* Nest.                */
  878.                     cwarn("Nested comments", NULLST);
  879.                                                 /* Fall into * stuff    */
  880.                 case '*':
  881.                     if ((c = get()) != '/')     /* If comment doesn't   */
  882.                         goto test;              /* end, look at next    */
  883.                     instring = FALSE;           /* End of comment,      */
  884.                     if (keepcomments) {         /* Put out the comment  */
  885.                         cput(c);                /* terminator, too      */
  886.                     }
  887.                     /*
  888.                      * A comment is syntactically "whitespace" --
  889.                      * however, there are certain strange sequences
  890.                      * such as
  891.                      *          #define foo(x)  (something)
  892.                      *                  foo|* comment *|(123)
  893.                      *       these are '/' ^           ^
  894.                      * where just returning space (or COM_SEP) will cause
  895.                      * problems.  This can be "fixed" by overwriting the
  896.                      * '/' in the input line buffer with ' ' (or COM_SEP)
  897.                      * but that may mess up an error message.
  898.                      * So, we peek ahead -- if the next character is
  899.                      * "whitespace" we just get another character, if not,
  900.                      * we modify the buffer.  All in the name of purity.
  901.                      */
  902.                     if (*file->bptr == '\n'
  903.                      || type[*file->bptr & 0xFF] == SPA)
  904.                         goto newline;
  905. #if COMMENT_INVISIBLE
  906.                     /*
  907.                      * Return magic (old-fashioned) syntactic space.
  908.                      */
  909.                     return ((file->bptr[-1] = COM_SEP));
  910. #else
  911.                     return ((file->bptr[-1] = ' '));
  912. #endif
  913.  
  914.                 case '\n':                      /* we'll need a #line   */
  915.                     if (!keepcomments)
  916.                         wrongline = TRUE;       /* later...             */
  917.                 default:                        /* Anything else is     */
  918.                     break;                      /* Just a character     */
  919.                 }                               /* End switch           */
  920.             }                                   /* End comment loop     */
  921.         }                                       /* End if in comment    */
  922.         else if (!inmacro && c == '\\') {       /* If backslash, peek   */
  923.             if ((c = get()) == '\n') {          /* for a <nl>.  If so,  */
  924.                 wrongline = TRUE;
  925.                 goto newline;
  926.             }
  927.             else {                              /* Backslash anything   */
  928.                 unget();                        /* Get it later         */
  929.                 return ('\\');                  /* Return the backslash */
  930.             }
  931.         }
  932.         else if (c == '\f' || c == VT)          /* Form Feed, Vertical  */
  933.             c = ' ';                            /* Tab are whitespace   */
  934.         return (c);                             /* Just return the char */
  935. }
  936.  
  937.  
  938. #if OK_TRIGRAPH
  939.  
  940. #define TRIOFFSET       9
  941. static char     tritext[] = "=(/)'<!>-\0#[\\]^{|}~";
  942. /*                           ^          ^
  943.  *                           +----------+
  944.  *                        this becomes this
  945.  */
  946.  
  947. trigraph(in)
  948. register char           *in;
  949. /*
  950.  * Perform in-place trigraph replacement on an input text line.
  951.  * This was added to the Draft Standard.  In an input text
  952.  * line, the sequence ??<something> is transformed to a character
  953.  * (which might not appear on the input keyboard.)
  954.  * There are problems with trigraphs, and this code may not last long.
  955.  */
  956. {
  957.         register char   *tp;
  958.         extern char     *strchr();
  959.  
  960.         while ((in = strchr(in, '?')) != NULLST) {
  961.             if (*++in != '?')
  962.                 continue;
  963.             while (*++in == '?')
  964.                 ;
  965.             if ((tp = strchr(tritext, *in)) == NULLST)
  966.                 continue;
  967.             in[-2] = tp[TRIOFFSET];
  968.             in--;
  969.             strcpy(in, in + 2);
  970.         }
  971. }
  972. #endif
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986. unget()
  987. /*
  988.  * Backup the pointer to reread the last character.  Fatal error
  989.  * (code bug) if we backup too far.  unget() may be called,
  990.  * without problems, at end of file.  Only one character may
  991.  * be ungotten.  If you need to unget more, call ungetstring().
  992.  */
  993. {
  994.         register FILEINFO       *file;
  995.  
  996.         if ((file = infile) == NULL)
  997.             return;                     /* Unget after EOF              */
  998.         if (--file->bptr < file->buffer)
  999.             cfatal("Too much pushback", NULLST);
  1000.         if (*file->bptr == '\n')        /* Ungetting a newline?         */
  1001.             --line;                     /* Unget the line number, too   */
  1002. #if DEBUG
  1003.         if (debug > 2)
  1004.             dumpunget("after unget");
  1005. #endif
  1006. }
  1007.  
  1008. ungetstring(text)
  1009. char            *text;
  1010. /*
  1011.  * Push a string back on the input stream.  This is done by treating
  1012.  * the text as if it were a macro.
  1013.  */
  1014. {
  1015.         register FILEINFO       *file;
  1016.         extern FILEINFO         *getfile();
  1017.  
  1018.         file = getfile(strlen(text) + 1, "");
  1019.         strcpy(file->buffer, text);
  1020. }
  1021.  
  1022. int
  1023. cget()
  1024. /*
  1025.  * Get one character, absorb "funny space" after comments or
  1026.  * token concatenation
  1027.  */
  1028. {
  1029.         register int    c;
  1030.  
  1031.         do {
  1032.             c = get();
  1033. #if COMMENT_INVISIBLE || CON_NOEXPAND
  1034.         } while (c == TOK_SEP || c == COM_SEP);
  1035. #else
  1036.         } while (c == TOK_SEP);
  1037. #endif
  1038.         return (c);
  1039. }
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057.  
  1058. /*
  1059.  * Error messages and other hacks.  The first byte of severity
  1060.  * is 'S' for string arguments and 'I' for int arguments.  This
  1061.  * is needed for portability with machines that have int's that
  1062.  * are shorter than  char *'s.
  1063.  */
  1064.  
  1065. static
  1066. domsg(severity, format, arg)
  1067. char            *severity;              /* "Error", "Warning", "Fatal"  */
  1068. char            *format;                /* Format for the error message */
  1069. char            *arg;                   /* Something for the message    */
  1070. /*
  1071.  * Print filenames, macro names, and line numbers for error messages.
  1072.  */
  1073. {
  1074.         register char           *tp;
  1075.         register FILEINFO       *file;
  1076.  
  1077.         fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
  1078.         if (*severity == 'S')
  1079.             fprintf(stderr, format, arg);
  1080.         else
  1081.             fprintf(stderr, format, (int) arg);
  1082.         putc('\n', stderr);
  1083.         if ((file = infile) == NULL)
  1084.             return;                             /* At end of file       */
  1085.         if (file->fp != NULL) {
  1086.             tp = file->buffer;                  /* Print current file   */
  1087.             fprintf(stderr, "%s", tp);          /* name, making sure    */
  1088.             if (tp[strlen(tp) - 1] != '\n')     /* there's a newline    */
  1089.                 putc('\n', stderr);
  1090.         }
  1091.         while ((file = file->parent) != NULL) { /* Print #includes, too */
  1092.             if (file->fp == NULL)
  1093.                 fprintf(stderr, "from macro %s\n", file->filename);
  1094.             else {
  1095.                 tp = file->buffer;
  1096.                 fprintf(stderr, "from file %s, line %d:\n%s",
  1097.                     (file->progname != NULL)
  1098.                         ? file->progname : file->filename,
  1099.                     file->line, tp);
  1100.                 if (tp[strlen(tp) - 1] != '\n')
  1101.                     putc('\n', stderr);
  1102.             }
  1103.         }
  1104. }
  1105.  
  1106. cerror(format, sarg)
  1107. char            *format;
  1108. char            *sarg;          /* Single string argument               */
  1109. /*
  1110.  * Print a normal error message, string argument.
  1111.  */
  1112. {
  1113.         domsg("SError", format, sarg);
  1114.         errors++;
  1115. }
  1116.  
  1117. cierror(format, narg)
  1118. char            *format;
  1119. int             narg;           /* Single numeric argument              */
  1120. /*
  1121.  * Print a normal error message, numeric argument.
  1122.  */
  1123. {
  1124.         domsg("IError", format, (char *) narg);
  1125.         errors++;
  1126. }
  1127.  
  1128. cfatal(format, sarg)
  1129. char            *format;
  1130. char            *sarg;                  /* Single string argument       */
  1131. /*
  1132.  * A real disaster
  1133.  */
  1134. {
  1135.         domsg("SFatal error", format, sarg);
  1136.         exit(IO_ERROR);
  1137. }
  1138.  
  1139. cwarn(format, sarg)
  1140. char            *format;
  1141. char            *sarg;                  /* Single string argument       */
  1142. /*
  1143.  * A non-fatal error, string argument.
  1144.  */
  1145. {
  1146.         domsg("SWarning", format, sarg);
  1147. }
  1148.  
  1149. ciwarn(format, narg)
  1150. char            *format;
  1151. int             narg;                   /* Single numeric argument      */
  1152. /*
  1153.  * A non-fatal error, numeric argument.
  1154.  */
  1155. {
  1156.         domsg("IWarning", format, (char *) narg);
  1157. }
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178. #if DEBUG
  1179. /*
  1180.  * Things are getting worse, please send chocolate.
  1181.  */
  1182. dumpdef(why)
  1183. char            *why;
  1184. /*
  1185.  * Dump current macro definition to output stream.
  1186.  */
  1187. {
  1188.         register DEFBUF         *dp;
  1189.         register DEFBUF         **syp;
  1190.  
  1191.         printf("CPP symbol table dump %s\n", why);
  1192.         for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
  1193.             if ((dp = *syp) != (DEFBUF *) NULL) {
  1194.                 printf("symtab[%d]\n", (syp - symtab));
  1195.                 do {
  1196.                     dumpadef((char *) NULL, dp);
  1197.                 } while ((dp = dp->link) != (DEFBUF *) NULL);
  1198.             }
  1199.         }
  1200. }
  1201.  
  1202. dumpadef(why, dp)
  1203. char            *why;                   /* Notation                     */
  1204. register DEFBUF *dp;
  1205. /*
  1206.  * Dump a specific macro definition.
  1207.  */
  1208. {
  1209.         printf(" \"%s\" [%d]", dp->name, dp->nargs);
  1210.         dumpstring(why, dp->repl);
  1211. }
  1212.  
  1213. dumpstring(why, text)
  1214. char            *why;
  1215. char            *text;
  1216. /*
  1217.  * Dump text readably.
  1218.  */
  1219. {
  1220.         register char           *cp;
  1221.         register int            c;
  1222.  
  1223.         if (why != NULL)
  1224.             printf(" (%s)", why);
  1225.         printf(" => ");
  1226.         if (text == NULL)
  1227.             printf("NULL");
  1228.         else {
  1229.             for (cp = text; (c = *cp++ & 0xFF) != EOS;) {
  1230.                 if (c == MAC_PARM)
  1231.                     printf("<%d>", *cp++ & 0xFF);
  1232.                 else if (isprint(c) || c == '\n' || c == '\t')
  1233.                     putchar(c);
  1234.                 else if (c == TOK_SEP)
  1235.                     printf("<TSEP>");
  1236.                 else if (c == COM_SEP)
  1237.                     printf("<CSEP>");
  1238.                 else if (c == DEF_MAGIC)
  1239.                     printf("<MAGIC>");
  1240.                 else if (c == ST_QUOTE)
  1241.                     printf("<QUOTE>");
  1242.                 else if (c < ' ')
  1243.                     printf("<^%c>", c + '@');
  1244.                 else
  1245.                     printf("<\\0%o>", c);
  1246.             }
  1247.         }
  1248.         putchar('\n');
  1249. }
  1250.  
  1251. dumpunget(why)
  1252. char            *why;
  1253. /*
  1254.  * Dump all ungotten junk (pending macros and current input lines).
  1255.  */
  1256. {
  1257.         register FILEINFO       *file;
  1258.  
  1259.         printf("dump of pending input text");
  1260.         if (why != NULL)
  1261.             printf("-- %s", why);
  1262.         putchar('\n');
  1263.         for (file = infile; file != NULL; file = file->parent) {
  1264.             if (file->fp == NULL)
  1265.                 dumpstring(file->filename, file->bptr);
  1266.             else if (file->progname != NULL)
  1267.                 dumpstring(file->progname, file->bptr);
  1268.             else dumpstring(file->filename, file->bptr);
  1269.         }
  1270. }
  1271. #endif
  1272.  
  1273.  
  1274.